import tkinter as tk
from tkinter import ttk
from tkinter import PhotoImage
import tkinter.messagebox as messagebox

class SerialPortUI:
    def __init__(self, root):
        self.root = root
        self.root.title("串口调试助手")
        # 使用 .png 文件设置图标
        icon_path = "serial.png"
        self.icon = PhotoImage(file=icon_path)
        self.root.iconphoto(True, self.icon)

        # 设置窗口居中
        self.center_window(800, 600)

        # 配置行列权重以实现自适应
        self.root.rowconfigure(0, weight=1)
        self.root.columnconfigure(0, weight=1)

        # 主框架，分为左右两部分
        self.main_frame = ttk.Frame(root)
        self.main_frame.grid(row=0, column=0, sticky="nsew")
        self.main_frame.rowconfigure(0, weight=1)
        self.main_frame.columnconfigure(1, weight=1)  # 右侧部分可拉伸

        # 左侧串口设置区域
        self.port_frame = ttk.LabelFrame(self.main_frame, text="串口设置", width=200)
        self.port_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ns")
        self.port_frame.grid_propagate(False)  # 固定宽度
        self.port_frame.columnconfigure(1, weight=1)  # 使控件适应宽度

        # 串口端口选择标签和下拉框
        self.port_label = ttk.Label(self.port_frame, text="端口名：")
        self.port_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.port_combobox = ttk.Combobox(self.port_frame, values='', state="readonly")
        self.port_combobox.grid(row=0, column=1, padx=5, pady=5, sticky="ew")

        # 波特率选择标签和下拉框
        self.baud_label = ttk.Label(self.port_frame, text="波特率：")
        self.baud_label.grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.baud_combobox = ttk.Combobox(self.port_frame, values=[300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600], state="readonly")
        self.baud_combobox.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        self.baud_combobox.set(115200)  # 默认设置为 115200 波特率

        # 数据位选择
        self.data_bits_label = ttk.Label(self.port_frame, text="数据位：")
        self.data_bits_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.data_bits_combobox = ttk.Combobox(self.port_frame, values=[5, 6, 7, 8], state="readonly")
        self.data_bits_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        self.data_bits_combobox.set(8)  # 默认设置为 8 数据位

        # 校验位选择
        self.parity_label = ttk.Label(self.port_frame, text="校验位：")
        self.parity_label.grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.parity_combobox = ttk.Combobox(self.port_frame, values=["None", "Even", "Odd", "Mark", "Space"], state="readonly")
        self.parity_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="ew")
        self.parity_combobox.set("None")  # 默认设置为无校验

        # 停止位选择
        self.stop_bits_label = ttk.Label(self.port_frame, text="停止位：")
        self.stop_bits_label.grid(row=4, column=0, padx=5, pady=5, sticky="w")
        self.stop_bits_combobox = ttk.Combobox(self.port_frame, values=[1, 1.5, 2], state="readonly")
        self.stop_bits_combobox.grid(row=4, column=1, padx=5, pady=5, sticky="ew")
        self.stop_bits_combobox.set(1)  # 默认设置为 1 停止位

        # 打开/关闭串口的按钮（合并为一个按钮）
        self.toggle_button = ttk.Button(self.port_frame, text="打开串口", command='')
        self.toggle_button.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky="ew")

        # 右侧数据发送和接收区域
        self.data_frame = ttk.Frame(self.main_frame)
        self.data_frame.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
        self.data_frame.rowconfigure(0, weight=1)
        self.data_frame.rowconfigure(1, weight=0)
        self.data_frame.columnconfigure(0, weight=1)

        # 数据接收区域
        self.receive_frame = ttk.LabelFrame(self.data_frame, text="接收数据")
        self.receive_frame.grid(row=0, column=0, sticky="nsew")
        self.receive_frame.rowconfigure(0, weight=1)
        self.receive_frame.columnconfigure(0, weight=1)

        self.receive_text = tk.Text(self.receive_frame, state="disabled", wrap="word")
        self.receive_text.grid(row=0, column=0, sticky="nsew")

        self.receive_scrollbar = ttk.Scrollbar(self.receive_frame, command='')
        self.receive_text.config(yscrollcommand=self.receive_scrollbar.set)
        self.receive_scrollbar.grid(row=0, column=1, sticky="ns")

        # 数据发送区域
        self.send_frame = ttk.LabelFrame(self.data_frame, text="发送数据")
        self.send_frame.grid(row=1, column=0, sticky="ew")
        self.send_frame.columnconfigure(0, weight=1)


        self.send_entry = ttk.Entry(self.send_frame)
        self.send_entry.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
        self.send_button = ttk.Button(self.send_frame, text="发送", command='')
        self.send_button.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        # 绑定回车键发送数据
        self.send_entry.bind("<Return>", lambda event: self.send_button.invoke())

        # 初始化串口连接和监听状态
        self.serial_connection = None
        self.is_listening = False

    def center_window(self, width, height):
        """将窗口居中显示"""
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - width) // 2
        y = (screen_height - height) // 2
        self.root.geometry(f"{width}x{height}+{x}+{y}")

    def messagebox(self, title, message, type="info"):
        """显示消息框"""
        if type == "info":
            messagebox.showinfo(title, message)
        elif type == "warning":
            messagebox.showwarning(title, message)
        elif type == "error":
            messagebox.showerror(title, message)

    def set_toggle_button_command(self, command):
        """设置打开/关闭串口按钮的命令"""
        self.toggle_button.config(command=command)

    def set_serial_ports(self, ports):
        """设置串口下拉框的可选项"""
        self.port_combobox['values'] = [port.device for port in ports]
        if ports:
            self.port_combobox.current(0)

    def set_toggle_button_text(self, text):
        """设置打开/关闭串口按钮的文本和命令"""
        self.toggle_button.config(text=text)
    
    def set_send_button_command(self, command):
        """设置发送按钮的命令"""
        self.send_button.config(command=command)
    
    def set_receive_text(self, data):
        """设置接收数据"""
        self.root.after(0, self.update_receive_text, data)  # 使用 after 方法更新 UI


    def update_receive_text(self, data):
        """更新接收数据文本框"""
        self.receive_text.config(state="normal")
        self.receive_text.insert(tk.END, f"{data}")
        self.receive_text.see(tk.END)  # 自动滚动到文本框底部
        self.receive_text.config(state="disabled")

    def get_serial_settings(self):
        """返回串口设置的数据"""
        return {
            "port": self.port_combobox.get(),
            "baudrate": int(self.baud_combobox.get()),
            "data_bits": int(self.data_bits_combobox.get()),
            "parity": self.parity_combobox.get(),
            "stop_bits": float(self.stop_bits_combobox.get())
        }    
    def get_send_data(self):
        """获取发送数据"""
        return self.send_entry.get()